/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - RMI Client, FileChooser and WebDAV
 */
package de.ipk_gatersleben.bit.bi.edal.webdav.wrapper;

import java.io.IOException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataDirectoryException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.PrimaryDataEntityVersion;
import de.ipk_gatersleben.bit.bi.edal.primary_data.file.EdalException;
import de.ipk_gatersleben.bit.bi.edal.primary_data.security.EdalAuthenticateException;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientDataManager;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataDirectory;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntity;
import de.ipk_gatersleben.bit.bi.edal.rmi.client.ClientPrimaryDataEntityVersion;

/**
 * Handles any access to the eDAL file system.
 * 
 * @author benz
 * 
 *         TODO comment TODO createFile, createFolder TODO move folders, files
 */

public class FileSystemHandler {
	public static String VIRTUALVERSIONFOLDERPREFIX = ".versions";
	public static String VIRTUALFILEPREFIX = "!";
	public static String VIRTUALFOLDERPREFIX = "+";
	public static String HOST;
	public static int REGISTRY_PORT;
	private ClientPrimaryDataDirectory rootDirectory;
	private Map<String, ClientPrimaryDataEntity> innermap = new HashMap<String, ClientPrimaryDataEntity>();

	static {

		final Properties prop = new Properties();

		/* load webDAV-Properties */
		try {
			prop.load(FileSystemHandler.class
					.getResourceAsStream("/eDALwebDAV.properties"));

			if (System.getProperty("edalhost") == null) {
				HOST = prop.getProperty("server.host");
				ClientDataManager.logger.info("eDAL-Host = " + HOST);
			} else {
				HOST = System.getProperty("edalhost");
				ClientDataManager.logger.info("eDAL-Host = " + HOST);
			}
			if (System.getProperty("edalport") == null) {
				REGISTRY_PORT = Integer.parseInt(prop
						.getProperty("server.port"));
				ClientDataManager.logger.info("eDAL-Port = " + REGISTRY_PORT);
			} else {
				REGISTRY_PORT = Integer
						.parseInt(System.getProperty("edalport"));
				ClientDataManager.logger.info("eDAL-Port = " + REGISTRY_PORT);
			}

		} catch (final IOException e) {
			ClientDataManager.logger.fatal(
					"error loading FileSystemHandler properties", e);
			System.exit(-1);
		}
	}

	/**
	 * Constructor authenticate user, start RMI client and load root directory.
	 * 
	 * @throws RemoteException
	 * @throws NotBoundException
	 * @throws PrimaryDataDirectoryException
	 * @throws EdalAuthenticateException
	 * @throws EdalException
	 */
	public FileSystemHandler(ClientPrimaryDataDirectory rootDirectory)
			throws RemoteException, NotBoundException,
			PrimaryDataDirectoryException, EdalAuthenticateException,
			EdalException {
		this.rootDirectory = rootDirectory;
	}

	public void removecache(String path) {
		if (path != null && path.length() > 1) {
			innermap.remove(path.substring(1));
		}
	}

	/**
	 * Returns a {@link ClientPrimaryDataEntity}-Object represented by
	 * <code>path</code> or null if it doesn't exist.
	 * 
	 * @param path
	 *            the path to the <code>PrimayDataEntity</code>
	 * @return a <code>PrimayDataEntity</code>-Object or null
	 * @throws PrimaryDataDirectoryException
	 * @throws RemoteException
	 */
	public ClientPrimaryDataEntity getEntity(final String path)
			throws RemoteException, PrimaryDataDirectoryException {
		if (path.equals("/")) {
			return this.rootDirectory;
		}

		final String[] dirs = path.split("\\/");
		String tmpPath = "";

		ClientPrimaryDataDirectory dir = this.rootDirectory;
		ClientPrimaryDataEntity entity = dir;

		if (dirs.length > 1) {
			for (int i = 1; i < dirs.length; i++) {
				if (!dirs[i].isEmpty()) {
					tmpPath += "/" + dirs[i];

					ClientPrimaryDataEntity cacheobj = innermap.get(tmpPath);
					if (cacheobj != null) {
						entity = cacheobj;
						if (entity.isDirectory()) {
							dir = (ClientPrimaryDataDirectory) entity;
						} else {
							if (tmpPath.compareTo(path) == 0) {
								return entity;
							}
						}
						continue;
					}

					if (dir.exist(dirs[i])) {
						entity = dir.getPrimaryDataEntity(dirs[i]);
						if (entity.isDirectory()) {
							innermap.put(tmpPath, entity);
							dir = (ClientPrimaryDataDirectory) entity;
						} else {
							if (i == dirs.length - 2) {
								if (dirs[i].equals(dirs[i + 1])) {
									return entity;
								} else {
									return null;
								}
							} else {
								return entity;
							}
						}
					} else {
						return null;
					}
				}
			}
			if (tmpPath.compareTo(path) == 0
					|| path.compareTo(entity.getPath()) == 0
					|| tmpPath.compareTo(entity.getPath().substring(1)) == 0) {
				return entity;
			} else {
				return null;
			}

		} else {
			return dir;
		}
	}

	/**
	 * Get a {@link PrimaryDataEntityVersion} for a specific version represented
	 * by <code>version</code>.
	 * 
	 * @param entity
	 *            the {@link ClientPrimaryDataEntity} to get the version from
	 * @param version
	 *            the string representation of the version
	 * @return the requested version
	 * @throws RemoteException
	 */
	public static ClientPrimaryDataEntityVersion getVersion(
			final ClientPrimaryDataEntity entity, final long version)
			throws RemoteException {
		Iterator<ClientPrimaryDataEntityVersion> it;
		it = entity.getVersions().iterator();
		while (it.hasNext()) {
			final ClientPrimaryDataEntityVersion curr = it.next();
			if (curr.getRevision() == version) {
				return curr;
			}
		}
		return null;
	}
}